﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Internal.Util;
using NGuice.Inject.Binder;
using NGuice.Inject.Spi;
using NGuice.Inject.Matcher;
using System.Reflection;

namespace NGuice.Inject
{
    /// <summary>
    /// 私有模块的配置信息默认在其环境中是隐藏的，对其他模块和注入器的用户来说，仅仅显式暴露的bindings才有效。
    /// 私有模块可能暴露他创建的bindings和他安装的模块的bindings。一个私有模块能够被嵌入到一个规则的模块中
    /// 或者被另一个私有模块使用<code>Binder.Install()</code>安装。其bindings生命周期是在其继承的bindings的新环境中，
    /// 类型转换、scope、拦截器都在其父环境中。当你嵌套多个私有模块时，结果就是以injector注入器环境为根的一棵环境树
    /// NGuice EDSL bindings能够使用<code>expose（Type）</code>暴露，而Provide绑定能够使用Exposed元特性暴露：
    ///  <code>
    ///  public class FooBarBazModule extends PrivateModule {
    ///     protected void Configure() {
    ///         Bind(typeof(Foo)).To(typeof(RealFoo));
    ///         Expose(typeof(Foo));
    ///         Install(new TransactionalBarModule());
    ///         Expose(Bar.class).AnnotatedWith(typeof(Transactional));
    ///         Bind(SomeImplementationDetail.class);
    ///         Install(new MoreImplementationDetailsModule());
    ///    }
    ///    
    ///    [Provides]
    ///    [Exposed]
    ///    public Baz ProvideBaz() {
    ///         return new SuperBaz();
    ///    }
    /// }
    /// </code>
    /// 私有模块将使用<code>Injector.CreateChildInjector(Module[])</code>实现。当他能够适合他们的依赖时，
    /// 即时bindings将在根环境中被创建。这种bindings将会在树的所有环境中共享。bindings的scope被约束在他的
    /// 环境中。私有模块的一个单例边界在其环境中是唯一的，但相同类型不同私有模块中的一个binding绑定就是
    /// 不同的实例。注入注入器的一个共享的bindings能获取根注入器，此根注入器仅仅能够访问根环境的bindings。
    /// 注入注入器的一个显式的binding能够访问子环境中的所有bindings。注入注入器的一个共享的bindings能
    /// 获取根注入器，此根注入器仅仅能够访问根环境的bindings。注入注入器的一个显式的binding能够访问
    /// 子环境中的所有bindings
    /// </summary>
    public abstract class PrivateModule : IModule
    {
        /// <summary>
        ///  类似抽象模块，当前私有模块的绑定器
        /// </summary>
        private IPrivateBinder binder;

        public void Configure(IBinder binder)
        {
            Preconditions.CheckState(this.binder == null, "Re-entry is not allowed.");

            // Guice treats PrivateModules specially and passes in a PrivateBinder automatically.
            // NGuice特殊对待PrivateModules并在一个PrivateBinder中自动传递
            this.binder = (IPrivateBinder)binder.SkipSources(typeof(PrivateModule));
            try
            {
                Configure();
            }
            finally
            {
                this.binder = null;
            }
        }

        /// <summary>
        /// 创建bindings和其他对此模块私有的配置。在此模块中可以使用<code>Expose(Type)</code>
        /// 方法将bindings暴露给外部有效。
        /// </summary>
        protected abstract void Configure();

        /// <summary>
        /// Makes the binding for {@code key} available to other modules and the injector
        /// 将指定key的bindings暴露给其他模块或注入器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        protected virtual void Expose<T>(Key<T> key)
        {
            binder.Expose(key);
        }

        /// <summary>
        /// 对其他模块和注册器暴露binding。他使用<code>AnnotatedElementBuilder.AnnotatedWith(Type)</code>暴露具有一个binding元特性注释的类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        protected virtual IAnnotatedElementBuilder Expose(Type type)
        {
            return binder.Expose(type);
        }

        // everything below is copied from AbstractModule
        protected virtual IPrivateBinder Binder()
        {
            return binder;
        }

        protected virtual void BindScope<T>(IScope scope)
            where T : Attribute
        {
            binder.BindScope<T>(scope);
        }

        protected virtual ILinkedBindingBuilder<T> Bind<T>(Key<T> key)
        {
            return binder.Bind(key);
        }

        protected virtual IAnnotatedBindingBuilder<T> Bind<T>()
        {
            return binder.Bind<T>();
        }

        protected virtual IAnnotatedConstantBindingBuilder BindConstant()
        {
            return binder.BindConstant();
        }

        protected virtual void Install(IModule module)
        {
            binder.Install(module);
        }

        protected virtual void AddError(String message, params object[] arguments)
        {
            binder.AddError(message, arguments);
        }

        protected virtual void AddError(Exception t)
        {
            binder.AddError(t);
        }

        protected virtual void AddError(Message message)
        {
            binder.AddError(message);
        }

        protected virtual void RequestInjection(object instance)
        {
            binder.RequestInjectionForNoGeneric(instance);
        }

        protected virtual void RequestStaticInjection(params Type[] types)
        {
            binder.RequestStaticInjection(types);
        }

        /*if[AOP]*/
        protected virtual void BindInterceptor(IMatcher<Type> classMatcher, IMatcher<MethodInfo> methodMatcher, params AopAlliance.Intercept.IMethodInterceptor[] interceptors)
        {
            binder.BindInterceptor(classMatcher, methodMatcher, interceptors);
        }
        /*end[AOP]*/

        protected virtual void RequireBinding<T>(Key<T> key)
        {
            binder.GetProvider(key);
        }

        protected virtual void RequireBinding<T>()
        {
            binder.GetProvider<T>();
        }

        protected virtual IProvider<T> GetProvider<T>(Key<T> key)
        {
            return binder.GetProvider(key);
        }

        protected virtual IProvider<T> GetProvider<T>()
        {
            return binder.GetProvider<T>();
        }

        protected virtual void ConvertToTypes(IMatcher<Type> typeMatcher,
            ITypeConverter converter)
        {
            binder.ConvertToTypes(typeMatcher, converter);
        }

        protected virtual Stage CurrentStage()
        {
            return binder.CurrentStage;
        }

        protected virtual IMembersInjector<T> getMembersInjector<T>()
        {
            return binder.GetMembersInjector<T>();
        }

        protected virtual void BindListener(IMatcher<Type> typeMatcher, ITypeListener listener)
        {
            binder.BindListener(typeMatcher, listener);
        }
    }
}
